
//Copyright 1997-2009 Syrinx Development, Inc.
//This file is part of the Syrinx Web Application Framework (SWAF).
// == BEGIN LICENSE ==
//
// Licensed under the terms of any of the following licenses at your
// choice:
//
//  - GNU General Public License Version 3 or later (the "GPL")
//    http://www.gnu.org/licenses/gpl.html
//
//  - GNU Lesser General Public License Version 3 or later (the "LGPL")
//    http://www.gnu.org/licenses/lgpl.html
//
//  - Mozilla Public License Version 1.1 or later (the "MPL")
//    http://www.mozilla.org/MPL/MPL-1.1.html
//
// == END LICENSE ==
using System;
using System.Collections;
using System.IO;
using System.ComponentModel;
using System.Globalization;
using System.Text;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

using Swaf;
using Swaf.BizObj;
using Swaf.Gui;
using Swaf.Gui.AspNet2;

namespace Calendars.Gui.AspNet
{
    [ToolboxData("<{0}:BizObjListCalendar runat=server></{0}:BizObjListCalendar>")]
    public class BizObjListCalendar : Swaf.Gui.AspNet2.UserControl, INamingContainer, IBizObjListCalendarDisplay, IPostBackEventHandler
    {
        static string s_clientScript;
        static string s_perCalScript;

        protected DayOfWeek m_firstDOW = DayOfWeek.Sunday;
        protected DateTime m_fromDate = DateTime.Now;
        protected int m_numDateRanges = 1;
        protected string m_width = "100%", m_height = "100%";
        protected int m_numRows = 0, m_maxRows = -1;
        protected int m_numCols = 0, m_numHeaderRows = 0;
        protected bool m_inFlow = true;
		protected string m_className = "";
		protected CultureInfo m_dateCulture;
		protected string m_onDateClick = null;
		protected IBizObj m_currentView = null;
		protected HtmlTextWriter m_writer = null;

        protected IDictionary m_singleDayContentData = new Hashtable();
        protected IDictionary m_multiDayContentData = new Hashtable();

		public BizObjListCalendar() : base() { m_fromDate = new DateTime(m_fromDate.Year, m_fromDate.Month, m_fromDate.Day); }
		public BizObjListCalendar(ActiveWidget widget) : base(widget) { m_fromDate = new DateTime(m_fromDate.Year, m_fromDate.Month, m_fromDate.Day); }

        static BizObjListCalendar()
        {
			StreamReader sr = new StreamReader(AssRez.Instance.getResource("Calendars.Gui.AspNet.ClientCalScript.js"));
			//StreamReader sr = new StreamReader(typeof(BizObjListCalendar).Assembly
			//    .GetManifestResourceStream("ScsAspNet.Syrinx.Gui.AspNet.ClientCalScript.js"));
            s_clientScript = sr.ReadToEnd();
            sr.Close();
			//sr = new StreamReader(AssRez.Instance.getResource("Calendars.Gui.AspNet.PerCalClientScript.js"));
			//sr = new StreamReader(typeof(BizObjListCalendar).Assembly
			//	.GetManifestResourceStream("Syrinx.Gui.AspNet.PerCalClientScript.js"));
			//s_perCalScript = sr.ReadToEnd();
            //sr.Close();
        }

		protected string m_parentIds;
		public override  BizProcWidgetType BizProcWidgetType { get { return BizProcWidgetType.list; } set { } }

		
        #region IBizObjListCalendarDisplay Members

        public void clearCalData()
        {
            Controls.Clear();
            m_singleDayContentData.Clear();
        }

        public void addBizObjList(IBizObj currentView, IBizObj partnerInfo, IBizObjList theList)
        {
			m_currentView = currentView;
            DateTime first = getFirstDate();
            DateTime toDate = getLastDate() + new TimeSpan(1, 0, 0, 0);

            string widgetClass = partnerInfo.get("widgetClass").ToString();
            if (widgetClass == "")
                widgetClass = "Calendars.Gui.AspNet.BasicCalendarItemDisplay,ScsAspNet";

            IBizObjCursor cur = theList.createCursor();
            DateTime date = DateTime.MinValue, endDate = DateTime.MinValue;
            bool isRange = (bool)partnerInfo.get("isRange");
            string dateField = partnerInfo.get("dateField").ToString();
            string endDateField = partnerInfo.get("endDateField").ToString();
            int curPos = 0;
            while (!cur.eof)
            {
                date = (DateTime)cur.currentElement.get(dateField);
                date = new DateTime(date.Year, date.Month, date.Day);
                if (endDateField != "")
                    endDate = (DateTime)cur.currentElement.get(endDateField);
                if ((date >= first && date <= toDate) || (isRange && endDate >= first && endDate <= toDate))
                {
                    ICalendarItemDisplay widget = Cmn.callCtor(widgetClass) as ICalendarItemDisplay;
                    if (widget != null)
                    {
                        if (widget is Control)
                        {
                            ((Control)widget).ID = partnerInfo.get("name").ToString() + date.DayOfYear.ToString();
                            Controls.Add((Control)widget);
                        }
                        widget.show(partnerInfo, cur);
                        if (isRange)
                            m_multiDayContentData[date] = new object[] { endDate, widget };
                        else
                        {
                            IList widgets = m_singleDayContentData[date] as IList;
                            if (widgets == null)
                                m_singleDayContentData[date] = widgets = new ArrayList();
                            widgets.Add(widget);
                        }
                    }
                }
                if (curPos == cur.currentPosition)
                    cur.moveNext();
                ++curPos;

            }
        }

        public DateTime[] calcRange()
        {
            DateTime[] range = new DateTime[] { getFirstDate(), getLastDate() };
            return range;
        }


        public DateTime SelectedDate
        {
            get
            {
                return FromDate;
            }
            set
            {
                FromDate = value;
            }
        }

        public DateTime FromDate
        {
            get { return m_fromDate; }
            set
            {
                m_fromDate = value;
                m_fromDate = new DateTime(m_fromDate.Year, m_fromDate.Month, m_fromDate.Day);
                putOffline("m_fromDate", m_fromDate);
            }
        }

        public DayOfWeek FirstDayOfWeek
        {
            get { return (DayOfWeek)getOffline("m_firstDOW"); }
            set { putOffline("m_firstDOW", value); }
        }

        public CalendarView CalendarFormat
        {
            get
            {
				if (getOffline("m_calFormat") == null)
                    return CalendarView.Day;
				return (CalendarView)getOffline("m_calFormat");
            }
            set
            {
				setCalendarFormat(value);
            }
        }

		protected CalendarView m_calFormat;
        public void setCalendarFormat(CalendarView format)
        {
            putOffline("m_calFormat", format);
        }

        public void moveNext()
        {
            switch (CalendarFormat)
            {
                case CalendarView.Day:
                    m_fromDate = m_fromDate.AddDays(1);
                    break;
                case CalendarView.Month:
				case CalendarView.TinyMonth:
                    m_fromDate = m_fromDate.AddMonths(1);
                    break;
                case CalendarView.Week:
                    m_fromDate = m_fromDate.AddDays(7);
                    break;
            }
            putOffline("m_fromDate", m_fromDate);
        }

        public void movePrev()
        {
            switch (CalendarFormat)
            {
                case CalendarView.Day:
                    m_fromDate = m_fromDate - new TimeSpan(1, 0, 0, 0);
                    break;
                case CalendarView.Month:
				case CalendarView.TinyMonth:
					if (m_fromDate.Month == 1)
                        m_fromDate = new DateTime(m_fromDate.Year - 1, 12, m_fromDate.Day);
                    else
                        m_fromDate = new DateTime(m_fromDate.Year, m_fromDate.Month - 1, m_fromDate.Day);
                    break;
                case CalendarView.Week:
                    m_fromDate = m_fromDate.Subtract(new TimeSpan(7, 0, 0, 0, 0));
                    break;
            }
            putOffline("m_fromDate", m_fromDate);
        }

		public void moveToday()
		{
		}

		public int NumRanges { get { return (int)getOffline("m_numDateRanges"); } set { putOffline("m_numDateRanges", value); } }
		#endregion

		public bool IsInFlow { get { return (bool)getOffline("m_inFlow"); } set { putOffline("m_inFlow", value); } }
		public int MaxRowsToDisplay { get { return m_maxRows; } set { m_maxRows = value; } }
		public string Width { get { return (string)getOffline("m_width"); } set { putOffline("m_width", value); } }
		public string Height { get { return (string)getOffline("m_height"); } set { putOffline("m_height", value); } }
		public string OnDateClick { get { return (string)getOffline("m_onDateClick"); } set { putOffline("m_onDateClick", value); } }

        public string ClassName { get { return (string)getOffline("m_className"); } set { putOffline("m_className", value); } }

        protected override void OnLoad(EventArgs e)
        {
            //base.OnLoad(e);
			if (!(BPC.ActiveWidgets.ContainsKey(WidgetId)))
			{
				ActiveWidget act = new ActiveWidget(this, BPC, State);
				BPC.defineActiveWidget(act);
				if (State.State.get("m_fromDate") != null)
					m_fromDate = (DateTime)State.State.get("m_fromDate");

				if (State.State.get("m_inFlow") == null)
					State.State.put("m_inFlow", m_inFlow);
				if (State.State.get("m_calFormat") == null)
					State.State.put("m_calFormat", CalendarFormat);
				if (State.State.get("m_width") == null)
					State.State.put("m_width", Width);
				if (State.State.get("m_height") == null)
					State.State.put("m_height", Height);
				if (State.State.get("m_className") == null)
					State.State.put("m_className", ClassName);
				if (State.State.get("m_numDateRanges") == null)
					State.State.put("m_numDateRanges", NumRanges);
				if (State.State.get("m_firstDOW") == null)
					State.State.put("m_firstDOW", FirstDayOfWeek);
				if (State.State.get("m_onDateClick") == null)
					State.State.put("m_onDateClick", OnDateClick);
			}
		}

		public string ViewTitle
		{
			get
			{
				if (m_writer != null)
				{
					switch (CalendarFormat)
					{
						case CalendarView.Day:
							getCalDayTitle(m_writer);
							break;
						case CalendarView.Month:
						case CalendarView.TinyMonth:
							getCalMonthTitle(m_writer, CalendarFormat);
							break;
						case CalendarView.Week:
							getCalWeekTitle(m_writer);
							break;
					}
				}
				return "";
			}
		}

        public string ViewBody
        {
			get
			{
				if (m_writer != null)
					switch (CalendarFormat)
					{
						case CalendarView.Day:
							getCalDayHtml(m_writer);
							break;
						case CalendarView.Month:
						case CalendarView.TinyMonth:
							getCalMonthHtml(m_writer, CalendarFormat);
							break;
						case CalendarView.Week:
							getCalWeekHtml(m_writer);
							break;
					}
				return "";
			}
		}

		public override string ContentName
		{
			get
			{
				if (m_currentView != null && !Cmn.IsEmpty(m_currentView.get("readOnlyTemplate")))
					return (string)m_currentView.get("readOnlyTemplate");
				return base.ContentName;
			}
			set
			{
			}
		}

		protected override void  Render(HtmlTextWriter writer)
		{
			m_writer = writer;
			string userCulture = Application.currentApp.resMgr.CurrentCulture.get("dotNetBaseCulture").ToString();
			if (Cmn.IsEmpty(userCulture))
				userCulture = Application.currentApp.resMgr.BuiltInCulture.get("dotNetBaseCulture").ToString();
			if (userCulture == "ko")
				userCulture = "ko-KR";
			m_dateCulture = new CultureInfo(userCulture, false);
			if (m_dateCulture.IsNeutralCulture)
				m_dateCulture = null;

			if (!Cmn.IsEmpty(m_currentView.get("readOnlyTemplate")))
				base.Render(writer);
			else
			{
				writer.Write(ViewTitle);
				writer.Write(ViewBody);
			}

			IDictionary macros = new Hashtable();
			if (m_numRows <= m_maxRows || m_maxRows < 0)
				macros["NumRows"] = m_numRows;
			else
				macros["NumRows"] = m_maxRows;
			macros["NumCols"] = m_numCols;
			macros["NumHeaderRows"] = m_numHeaderRows;
			macros["WeekView"] = (CalendarFormat == CalendarView.Week || CalendarFormat == CalendarView.Day) ? "true" : "false";
			macros["SizeToOuterParent"] = (m_width != "100%" || m_height != "100%") ? "false" : "true";
			macros["WidgetId"] = WidgetId;

			Page.ClientScript.RegisterStartupScript(GetType(), "BizObjCal", s_clientScript, true);
        }

        protected DateTime getFirstDate()
        {
            if (getOffline("m_fromDate") != null)
                FromDate = (DateTime)getOffline("m_fromDate");
            DateTime firstDate = m_fromDate;
            switch (CalendarFormat)
            {
                case CalendarView.Month:
				case CalendarView.TinyMonth:
					//Calculate what the first day should be for the first week.
                    firstDate = new DateTime(firstDate.Year, firstDate.Month, 1);
                    int d = (int)firstDate.DayOfWeek;
					d -= (int)FirstDayOfWeek;
                    if (d < 0) d += 7;
                    firstDate -= new TimeSpan(d, 0, 0, 0);
                    break;
                case CalendarView.Week:
                    d = (int)firstDate.DayOfWeek;
                    d -= (int)DayOfWeek.Monday;
                    if (d < 0) d += 7;
                    firstDate -= new TimeSpan(d, 0, 0, 0);
                    break;
            }

            return firstDate;
        }

        protected DateTime getLastDate()
        {
            DateTime lastDate = getFirstDate();

            switch (CalendarFormat)
            {
                case CalendarView.Month:
				case CalendarView.TinyMonth:
					int month = lastDate.Month;
                    int count = 1;
                    int maxcount = NumRanges;
                    if (lastDate.Month != m_fromDate.Month)
                        ++maxcount;
                    lastDate -= new TimeSpan(1, 0, 0, 0);

                    while (count <= maxcount)
                    {
                        lastDate += new TimeSpan(7, 0, 0, 0);
                        if (lastDate.Month != month)
                        {
                            month = lastDate.Month;
                            ++count;
                        }
                        if (((DateTime)(lastDate + new TimeSpan(1, 0, 0, 0))).Month != month && count == maxcount)
                            break;
                    }
                    break;
                case CalendarView.Week:
                    lastDate += new TimeSpan((7 * NumRanges) - 1, 0, 0, 0);
                    break;
            }

            return lastDate;
        }

		protected void getCalDayTitle(HtmlTextWriter writer)
		{
			writer.Write("<div class='CalTitle CalDayTitle'>");
			writer.Write(m_fromDate.ToString("dddd, MMMM d yyyy", m_dateCulture));
			writer.Write("</div>");
		}

        protected void getCalDayHtml(HtmlTextWriter writer)
        {
            DateTime first = m_fromDate;
            m_numRows = 1;
            m_numCols = 1;

            writer.Write("<div id='");
            writer.Write(first.Year);
            writer.Write(".");
            writer.Write(first.Month);
            writer.Write(".");
            writer.Write(first.Day);
            writer.Write("' class='day CalBody'><div class='content'>");

            IList widgets = m_singleDayContentData[first] as IList;
            if (widgets != null)
                foreach (Control disp in widgets)
                    disp.RenderControl(writer);

            writer.Write("</div></div>");
		}

        // weekView
		protected void getCalWeekTitle(HtmlTextWriter writer)
		{
		}

        protected void getCalWeekHtml(HtmlTextWriter writer)
        {
            m_numCols = 2;
            DateTime first = getFirstDate();
            DateTime toDate = getLastDate();

            bool wroteHeaderId = false;
			writer.Write(String.Format("<div class='{0}'>", ClassName));
			writer.Write(String.Format("<div id='{0}' class='calendarArea'", WidgetId));
            writer.Write(">");
            while (first <= toDate)
            {
                for (int weekDay = 1; weekDay <= 7; ++weekDay)
                {
                    writer.Write("<div class='DayInRange'");
                    writer.Write(">");
                    writer.Write("<div ");
                    if (!wroteHeaderId)
                    {
                        wroteHeaderId = true;
                        writer.Write("id='h1' ");
                    }
                    writer.Write("class='header'>");
                    writer.Write(first.ToString("dddd, MMM d",m_dateCulture));
                    writer.Write("</div>");

                    writer.Write("<div id='");
                    writer.Write(first.Year);
                    writer.Write("-");
                    writer.Write(first.Month);
                    writer.Write("-");
                    writer.Write(first.Day);
                    writer.Write("' class='day'><div class='contentDay'><div class='properties'>");
                    //TODO: Put Day contents here

                    IList widgets = m_singleDayContentData[first] as IList;
                    if (widgets != null)
                        foreach (Control disp in widgets)
                            disp.RenderControl(writer);

                    writer.Write("</div></div></div>");
                    first += new TimeSpan(1, 0, 0, 0);
                    writer.Write("</div>");
                }
                m_numRows += 3;
            }
            writer.Write("</div>");
			writer.Write(String.Format("</div>"));
		}

        // monthView
		protected void getCalMonthTitle(HtmlTextWriter writer, CalendarView level)
		{
		}

        protected void getCalMonthHtml(HtmlTextWriter writer, CalendarView level)
        {
            m_numCols = 7;
            m_numHeaderRows = 1;
            DateTime first = getFirstDate();
            DateTime toDate = getLastDate();

			writer.Write(String.Format("<div id='{0}' class='calendarArea {1}'", WidgetId, ClassName));
            writer.Write("><table id=t1 border=0 cellspacing=0 cellpadding=0 width='100%'><tr>");
            DateTime headerDay = first;
            for (int dow = 0; dow < 7; ++dow)
            {
				writer.Write("<td id='h1' style='width:14.2857%;'><div class='header'>");
				if (level == CalendarView.Month)
					writer.Write(headerDay.ToString("ddd", m_dateCulture));
				else
					writer.Write(headerDay.ToString("ddd", m_dateCulture)[0]);
                writer.Write("</div></td>");
                headerDay += new TimeSpan(1, 0, 0, 0);
            }
            writer.Write("</tr>");

            //Loop through and create div for each day of month.
            int lastMonth = -1;
            int nextMonth = m_fromDate.Month + 1;
            if (nextMonth == 13) nextMonth = 1;

            string dayClass = "DayInRange";
            if (first.Month == FromDate.Month)
                dayClass = "DayOutOfRange";
            while (first <= toDate)
            {
				int curMon = first.AddDays(-1).Month;
				int lastDayMonth = first.AddDays(6).Month;
				if (level == CalendarView.TinyMonth && lastDayMonth != curMon && first.AddDays(8) < toDate)
					writer.Write(string.Format("<tr class='calHeaderRow'><td colspan='7'>{0}</td></tr>", first.AddDays(7).ToString("MMMM yyyy")));

				writer.Write("<tr class='calDayRow'>");
                for (int weekDay = 1; weekDay <= 7; ++weekDay)
                {
                    IList widgets = m_singleDayContentData[first] as IList;
					string dispText = first.Day.ToString();
                    int mon = first.Month;
                    if (mon != lastMonth)
                    {
						if (level == CalendarView.Month)
						{
							dispText = first.ToString("MMMM d", m_dateCulture);
							if (dispText.Length > 6)
								dispText = first.ToString("MMM d", m_dateCulture);
						}
                        lastMonth = mon;
                        if (dayClass == "DayOutOfRange")
                            dayClass = "DayInRange";
                        else
                            dayClass = "DayOutOfRange";
                    }

					string cellCssClass = "";
                    string cellCssStyle = "";

                    if (widgets != null)
                        foreach (ICalendarItemDisplay calDisp in widgets)
                        {
                            calDisp.updateDayCellCssClass(ref cellCssClass);
                            calDisp.updateDayCellCssStyle(ref cellCssStyle);
                        }
                            
                    writer.Write("<td class='");
                    writer.Write(dayClass);
                    writer.Write("'><div onclick=\"");
                    writer.Write(getCellClickEventHandler(first));
					writer.Write("\" class='innerDay ");
                    writer.Write(cellCssClass);
                    writer.Write("'");
                    if(cellCssStyle != "" && cellCssStyle != null)
                    {
                        writer.Write(" style='");
                        writer.Write(cellCssStyle);
                        writer.Write("'");
                    }
                    writer.Write("><span class='DayOfMonth'>");
                    writer.Write(dispText);
                    writer.Write("</span><div class='properties'>");

                    /*
                    Control disp = m_multiDayContentData[first] as Control;
                    if (disp != null)
                    {
                        writer.Write(String.Format(
                            "<div id='multi{0}' style='position:absolute'>", 
                            ""));
                        disp.RenderControl(writer);
                        writer.Write("</div>");
                    }
                     */

                    if (widgets != null)
                        foreach (ICalendarItemDisplay disp in widgets)
                            if(disp is Control)
                                ((Control)disp).RenderControl(writer);

                    writer.Write("</div></div></td>");
                    first += new TimeSpan(1, 0, 0, 0);
                }
                writer.Write("</tr>");
                m_numRows++;
            }
            writer.Write("</table></div>\n");
		}

        protected virtual string getCellClickEventHandler(DateTime date)
        {
            string handler = Page.ClientScript.GetPostBackEventReference(this, date.ToShortDateString(), true);
            return handler;
        }

        #region IPostBackEventHandler Members

        public void RaisePostBackEvent(string eventArgument)
        {
            DateTime selDate = DateTime.Parse(eventArgument);

			ActiveBizProc bizproc = BPC.getActiveBizProc(State.ParentBizProcIds[0]);
			if (bizproc.BizProc is CalendarViewBizProc)
				((CalendarViewBizProc)bizproc.BizProc).selectDate(selDate);
        }

        #endregion
    }
}
